# encoding=utf-8

from seg_system.application_config import ApplicationConfig
from seg_common.Exception import *
import cv2 as cv
import numpy as np
import math


class BuilderCommon:
    """BuilderCommon
        Builder的工具类，主要用于验证，以及计算拼接位置
    """

    @staticmethod
    def ShapeTest(img_list: list):
        if len(img_list) < 1:
            raise ElementIsNotEnoughException("element list len is : {}".format(len(img_list)))

        if not isinstance(img_list[0], np.ndarray):
            raise TypeError("Please input numpy type array")

        if not img_list[0].dtype == np.uint8:
            raise TypeError("Mat type is not uint8")

        tmp_shape = img_list[0].shape

        for i in range(1, len(img_list)):
            if tmp_shape != img_list[i].shape:
                raise ShapeNotTheSameException("{} is not same as {}".format(tmp_shape, img_list[i].shape))

    @staticmethod
    def DownloadMat(mat):
        if isinstance(mat, np.ndarray):
            return mat
        elif isinstance(mat, cv.cuda_GpuMat):
            return mat.download()
        else:
            raise TypeError("Please input np.ndarray or cv.cuda_GpuMat")

    @staticmethod
    def UploadMat(mat: np.ndarray):
        s = cv.cuda_GpuMat()
        s.upload(mat)
        return s

    @staticmethod
    def MinRectangle(num_img: int):
        """MinRectangle:
            - 创建一个矩形，包裹所有图像，现在这个算法会造成空间浪费
            - 返回的矩阵中，1代表真实数据，0代表需要被填充的部分
        """
        min_edge = math.ceil(math.sqrt(num_img))

        numpy_matrix = []
        for i in range(min_edge):
            num_img -= min_edge
            if num_img >= 0:
                numpy_matrix.append([1] * min_edge)
            elif (-num_img) == min_edge:
                break
            else:
                numpy_matrix.append([1] * (min_edge + num_img) + [0] * (-num_img))
                num_img = 0

        return np.array(numpy_matrix)

    @staticmethod
    def BuildBigMatrix(img_shape: tuple, num_height: int, num_width: int,
                       stride: int = 0, data_type=np.uint8, **kwargs):
        m_h = img_shape[0] * num_height + (num_height - 1) * stride
        m_w = img_shape[1] * num_width + (num_width - 1) * stride
        if m_h > ApplicationConfig.SystemConfig.CUDA_CV_MAX_EDGE or m_w > ApplicationConfig.SystemConfig.CUDA_CV_MAX_EDGE:
            raise MatSizeOutOfRangeException("Input Height: {}, Width: {}".format(m_h, m_w))

        if len(img_shape) == 3:
            return np.zeros((m_h, m_w, img_shape[2]), dtype=data_type)
        return np.zeros((m_h, m_w), dtype=data_type)